/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础，根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求，进行代码调试和修改。
*/
#include "iic.h"
#include "intrins.h"
#define DELAY_TIME	10

sbit scl = P2 ^ 0;
sbit sda = P2^1;

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

// AD读取 
/*
读取到的是数字电压（0~255），看题目要求转换为（0~5）
0 -> 外部输入 
1 -> 光敏电阻 
2 -> 差分输入
3 -> 滑动变阻器（RB2）
*/
// 如果要开启DA输出，那么这里必须写0x4?，否则就是0x0?
unsigned char Ad_Read(unsigned char addr)
{
	unsigned char temp;
	
	//选择芯片为PCF
	I2CStart();
	I2CSendByte(0x90);//PCF在IIC的地址，最后的0代表写入操作
	I2CWaitAck();//等待接受信号
	I2CSendByte(addr);//发送需要转换的地址
	I2CWaitAck();//等待接受信号
	
	I2CStart();
	I2CSendByte(0x91);//PCF在IIC的地址，最后的1代表读取操作
	I2CWaitAck();//等待接受信号
	temp = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return temp;
}

// DA 写入 
/*
	写入的是数字电压（0~255），从板子外部的DA输出到是模拟电压（0~5）
*/
void Da_Write(unsigned char dat)
{
	
	//选择芯片为PCF
	I2CStart();
	I2CSendByte(0x90);//PCF在IIC的地址，最后的0代表写入操作
	I2CWaitAck();//等待接受信号
	I2CSendByte(0x41);//使能DA转换（最好和题目中需要读取的AD地址一样）
	I2CWaitAck();//等待接受信号
	I2CSendByte(dat);
	I2CWaitAck();//等待接受信号
}

//EEPROM 写入 
/*
str为写入的数组
addr为写入数据存放的首地址
num为写入的数据个数
*/
void EEPROM_Write(unsigned char *str,unsigned char addr,unsigned char num)
{
	//选择芯片为EEPROM
	I2CStart();
	I2CSendByte(0xa0);//EEPROM在IIC的地址，最后的0代表写入操作
	I2CWaitAck();//等待接受信号
	I2CSendByte(addr);//发送需要写入的地址
	I2CWaitAck();//等待接受信号
	
	while(num--)
	{
		I2CSendByte(*str++);
		I2CWaitAck();
		I2C_Delay(200);
	}
	I2CStop();
	//保证写入时序完全，部分板子需要给10个255
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
	I2C_Delay(255);
}

//EEPROM 读取
/*
str为读取的数组
addr为读取数据存放的首地址
num为读取的数据个数
*/
void EEPROM_Read(unsigned char *str,unsigned char addr,unsigned char num)
{
	//选择芯片为EEPROM
	I2CStart();
	I2CSendByte(0xa0);//EEPROM在IIC的地址，最后的0代表写入操作
	I2CWaitAck();//等待接受信号
	I2CSendByte(addr);//发送需要读取的地址
	I2CWaitAck();//等待接受信号
	
	I2CStart();
	I2CSendByte(0xa1);//EEPROM在IIC的地址，最后的1代表读取操作
	I2CWaitAck();//等待接受信号
	while(num--)
	{
		*str++ = I2CReceiveByte();
		if(num)
			I2CSendAck(0);
		else
			I2CSendAck(1);
	}
	I2CStop();
}